package com.bupt.base.file;

import com.bupt.annotation.MParam;
import com.bupt.exception.BaseException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

/**
 * 采用原生的方式对于对象的操作的序列化以及反序列化
 * 采用原生的 ObjectOutputStream 和 ObjectInputStream 整合文件对象的操作
 * 模版模式
 * D：序列化的类型 必须实现 Serializable 接口
 *
 * <pre>
 *     介绍：
 *          在平时的时候，我们肯定会对文件的操作十分的频繁，这个时候，我们需要一套公共的模式来对文件进行操作
 *          这个采用的是原生的方式对于对象的操作的序列化以及反序列化 使用 ObjectOutputStream 和 ObjectInputStream
 *          对于我们的文件进行操作，如果想采用 Protostuff 进行操作 请看 com.bupt.base.file.BaseFileOpt
 * </pre>
 *
 * @author breakpoint/赵先生 <zlgtop@163.com>
 * @see com.bupt.base.file.BaseOriginFileOpt Protostuff序列化以及反序列化
 * create on 2021/04/17
 */
public interface BaseOriginFileOpt<D extends Serializable> extends CommonFileOptMessage {
    // 日志的输出操作
    Logger log = LoggerFactory.getLogger(BaseOriginFileOpt.class);

    /**
     * 获取文件的位置 获取文件的绝对路径
     */
    default String getFilePath() {
        throw new UnsupportedOperationException("请重写该方法");
    }

    /**
     * 获取文件的后缀 文件的存储后缀
     */
    default String getFileSuffix() {
        throw new UnsupportedOperationException("请重写该方法");
    }

    // 获取文件的名字
    // 文件存储的绝对路径+文件名字 也可以自定义 这个返回值 但是 是 有 子类来进行实现的
    default String getAbsoluteFileName(@MParam("文件存储的位置") String path, @MParam("数据标识ID") String dataId) {
        return path + File.separator + dataId + getFileSuffix();
    }

    /**
     * 获取对象从文件中 dataId 可以是任意的 但是 存储 以及 取出 都应该是相同的
     */
    default D getObjectFromFile(@MParam("数据的ID") String dataId) throws BaseException {
        return this.getObjectFromFile(dataId, null);
    }

    /**
     * 获取对象从文件
     * 从特定的文件目录位置获取相关的数据
     */
    @SuppressWarnings("unchecked")
    default D getObjectFromFile(@MParam("数据的ID") String dataId,
                                @MParam("文件的存储路径") String path) throws BaseException {
        if (null == dataId || "".equals(dataId)) {
            return null;
        }
        // 如果文件路径的是空的话
        // 请求自定义的文件路径
        if (StringUtils.isBlank(path)) {
            // 获取文件存储的位置
            path = getFilePath();
        }
        // 文件夹
        File director = new File(path);
        if (!director.exists()) {
            return null;
        }
        // 获取文件的名字
        final String fileName = getAbsoluteFileName(path, dataId);
        File file = new File(fileName);
        if (!file.exists()) {
            return null;
        }
        ObjectInputStream ios = null;
        try {
            ios = new ObjectInputStream(new FileInputStream(file));
            return (D) ios.readObject();
        } catch (Exception e) {
            // throw
            log.error("对象获取失败 dataId:{}", dataId, e);
            // 返回 null
            return null;
        } finally {
            if (null != ios) {
                try {
                    ios.close();
                } catch (IOException e) {
                    log.error("文件操作出现异常", e);
                }
            }
        }
    }

    /**
     * 将对象写入对象 将特定的数据写入到 硬盘
     */
    default boolean saveObjectDataToFile(@MParam("对象数据") D data,
                                         @MParam("数据标识ID") String dataId) throws BaseException {
        return this.saveObjectDataToFile(data, dataId, null);
    }

    /**
     * 将对象写入对象 将特定的数据写入特定的文件夹下
     */
    default boolean saveObjectDataToFile(@MParam("对象数据") D data,
                                         @MParam("数据标识ID") String dataId,
                                         @MParam("存储路径") String path) throws BaseException {
        // 如果文件路径的是空的话
        // 请求自定义的文件路径
        if (StringUtils.isBlank(path)) {
            // 获取文件存储的位置
            path = getFilePath();
        }
        // 文件夹
        File director = new File(path);
        if (!director.exists()) {
            if (!director.mkdirs()) {
                // 创建失败的情况
                throw new BaseException("请授予当前用户创建文件夹的权限 path:" + path);
            }
        }
        // 获取绝对路径
        // 获取文件的名字
        final String fileName = getAbsoluteFileName(path, dataId);
        File file = new File(fileName);
        if (file.exists()) {
            boolean res = file.delete();
            // 删除存在的文件
        }
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream(file));
            oos.writeObject(data);
            return true;
        } catch (Exception e) {
            throw new BaseException(e.getMessage());
        } finally {
            if (null != oos) {
                try {
                    oos.close();
                } catch (IOException e) {
                    log.error("文件操作出现异常", e);
                }
            }
        }
    }

    /**
     * 删除 特定的ID的文件
     */
    default boolean deleteObjectData(@MParam("数据标识ID") String dataId) throws BaseException {
        return this.deleteObjectData(dataId, null);
    }

    /**
     * 删除特定的ID的文件
     * 删除特定文件夹下的文件
     */
    default boolean deleteObjectData(@MParam("数据标识ID") String dataId,
                                     @MParam("存储路径") String path) throws BaseException {
        if (StringUtils.isBlank(path)) {
            // 获取文件存储的位置
            path = getFilePath();
        }
        // 查看是否存储那个文件夹
        File director = new File(path);
        if (director.exists()) {
            // 获取绝对路径
            // 获取文件的名字
            final String fileName = getAbsoluteFileName(path, dataId);
            try {
                File file = new File(fileName);
                if (file.exists()) {
                    // 返回删除结果
                    return file.delete();
                }
            } catch (Exception e) {
                // nothing to do
            }
        }
        // 默认返回删除成功的
        return true;
    }

}
